Popular Searches
Popular Course Categories
Popular Courses

Preparing for iOS Lifecycle, View Controllers, SwiftUI, and UIKit Questions

Preparing for iOS Lifecycle, View Controllers, SwiftUI, and UIKit Questions

iOS App Development Portfolio and Interview Preparation

Preparing for iOS Lifecycle, View Controllers, SwiftUI, and UIKit Questions

Course: iOS App Development

Topic: Preparing for iOS Lifecycle, View Controllers, SwiftUI, and UIKit Questions

Course Link: iOS App Development Training

Demo Link: Register for a Course Demo

Website: JustAcademy


1. Introduction

Understanding the iOS application lifecycle, view controller lifecycle, SwiftUI, and UIKit is essential for building reliable iPhone and iPad applications. These concepts are also frequently discussed in iOS developer interviews because they demonstrate whether a developer understands how an application launches, displays content, responds to user interactions, handles background transitions, and manages its interface.

iOS provides two major user interface development approaches: UIKit and SwiftUI. UIKit uses view controllers, views, delegates, and imperative programming patterns. SwiftUI uses a declarative approach in which developers describe the interface based on application state. Both frameworks can be used independently or integrated into the same application.

This topic explains important lifecycle methods, application states, view controller callbacks, SwiftUI lifecycle concepts, UIKit components, framework differences, practical examples, and common interview questions.

2. Learning Objectives

  • Understand the iOS application lifecycle and its different states.
  • Explain the responsibilities of AppDelegate and SceneDelegate.
  • Understand the purpose and sequence of UIViewController lifecycle methods.
  • Learn how SwiftUI manages application and view lifecycles.
  • Understand the differences between UIKit and SwiftUI.
  • Learn how to manage navigation, state, and user interface updates.
  • Prepare answers for common iOS lifecycle and framework interview questions.
  • Demonstrate lifecycle concepts through practical Swift examples.

3. Understanding the iOS Application Lifecycle

The iOS application lifecycle describes the different states an application passes through during its execution. The operating system controls these transitions and informs the application when it becomes active, inactive, enters the background, or needs to respond to other system events.

3.1 Main Application States

State Description Typical Activity
Not Running The application has not been launched or has been terminated. No application code is currently executing.
Inactive The application is running but temporarily not receiving user events. Transitioning between active and background states or responding to interruptions.
Active The application is in the foreground and receiving user interactions. Handling taps, gestures, navigation, and interface updates.
Background The application is no longer visible but may receive limited execution time. Finishing permitted tasks and saving important application state.
Suspended The application remains in memory but does not execute code. Waiting until the operating system resumes or terminates it.

3.2 Typical Application State Flow

Not Running
     |
     v
Application Launch
     |
     v
Inactive
     |
     v
Active
     |
     v
Inactive
     |
     v
Background
     |
     v
Suspended
     |
     v
Terminated or Resumed

Important: iOS controls application scheduling and may terminate a suspended application when system resources are required. Developers should not assume that every application will receive a final termination callback before being removed from memory.

3.3 Why Application Lifecycle Management Is Important

  • Data protection: Save important information when an application moves away from the foreground.
  • Resource management: Stop unnecessary processing when the application is not visible.
  • User experience: Restore the interface when users return to the application.
  • Performance: Avoid unnecessary background operations.
  • Reliability: Handle interruptions, memory warnings, and system events correctly.

4. Understanding AppDelegate

AppDelegate is an object that manages application-level events and shared application behavior. It conforms to the UIApplicationDelegate protocol and receives callbacks associated with launching and managing the application process.

4.1 Responsibilities of AppDelegate

  • Perform application launch configuration.
  • Initialize shared services and application dependencies.
  • Configure notification handling.
  • Respond to application-level system events.
  • Coordinate application-wide functionality.

4.2 Important AppDelegate Methods

Method Purpose
application(_:didFinishLaunchingWithOptions:) Performs initial application setup after launch.
applicationWillResignActive(_:) Notifies the application that it is about to become inactive in an app-based lifecycle.
applicationDidEnterBackground(_:) Notifies the application that it entered the background in an app-based lifecycle.
applicationWillEnterForeground(_:) Notifies the application that it is moving toward the foreground in an app-based lifecycle.
applicationDidBecomeActive(_:) Notifies the application that it became active in an app-based lifecycle.
applicationWillTerminate(_:) Provides a termination callback in situations where the system calls it.

4.3 AppDelegate Example

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions:
        [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {

        print("Application launched")

        return true
    }

    func applicationDidBecomeActive(
        _ application: UIApplication
    ) {
        print("Application became active")
    }
}

Explanation: The launch callback is used to perform application-level initialization. The active-state callback can be used to refresh shared information or resume appropriate application-wide operations in an app-based lifecycle.

Interview point: In scene-based applications, many foreground and background user-interface lifecycle events are handled by SceneDelegate rather than the older AppDelegate callbacks.

5. Understanding SceneDelegate

SceneDelegate manages the lifecycle of an individual application interface, known as a scene. A scene represents one instance of the application's user interface. On supported devices, an application can have multiple scenes, and each scene can have its own state.

5.1 Responsibilities of SceneDelegate

  • Connect a scene to the application.
  • Create and configure the scene window when required.
  • Set the root view controller.
  • Respond to scene activation and background transitions.
  • Restore or clean up scene-specific resources.

5.2 Important SceneDelegate Methods

Method Purpose
scene(_:willConnectTo:options:) Connects a scene and configures its initial interface.
sceneDidBecomeActive(_:) Notifies that the scene became active.
sceneWillResignActive(_:) Notifies that the scene is about to become inactive.
sceneWillEnterForeground(_:) Notifies that the scene is moving toward the foreground.
sceneDidEnterBackground(_:) Notifies that the scene entered the background.
sceneDidDisconnect(_:) Notifies that the scene was disconnected and its resources may need cleanup.

5.3 SceneDelegate Example

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(
        _ scene: UIScene,
        willConnectTo session: UISceneSession,
        options connectionOptions: UIScene.ConnectionOptions
    ) {
        guard let windowScene = scene as? UIWindowScene else {
            return
        }

        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = ViewController()
        window.makeKeyAndVisible()

        self.window = window
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        print("Scene became active")
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        print("Scene entered background")
    }
}

Explanation: The scene connection method creates a window associated with the supplied UIWindowScene and assigns a root view controller. Other methods respond to the scene's state transitions.

5.4 AppDelegate vs SceneDelegate

AppDelegate SceneDelegate
Manages application-process-level events. Manages an individual user-interface scene.
Handles application launch configuration. Handles scene connection and interface setup.
Coordinates shared application services. Coordinates scene-specific windows and state.
One application process has an application delegate. An application may have multiple scene delegate instances.
Conforms to UIApplicationDelegate. Typically conforms to UIWindowSceneDelegate.

6. Understanding UIViewController

UIViewController is a fundamental UIKit class used to manage a screen or a portion of an application's interface. It controls the view hierarchy, coordinates user interactions, manages navigation, and responds to lifecycle events.

6.1 Responsibilities of a View Controller

  • Manage the screen's root view and child views.
  • Configure labels, buttons, images, and other interface elements.
  • Handle user interactions.
  • Coordinate data between the model and view.
  • Manage navigation and presentation of other view controllers.
  • Respond to layout and lifecycle events.

6.2 Creating a Basic UIViewController

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .systemBackground
        title = "Home Screen"

        print("View controller loaded")
    }
}

Explanation: The class inherits from UIViewController. The viewDidLoad method is overridden to configure the screen after its view hierarchy has loaded.

7. UIViewController Lifecycle Methods

UIViewController provides several lifecycle methods that notify developers when a view is loaded, about to appear, becomes visible, or is removed from the screen.

7.1 Important Lifecycle Methods

Method When It Is Called Common Use
loadView() When the controller needs its root view and no view has been provided. Create the view hierarchy programmatically.
viewDidLoad() After the view hierarchy has loaded into memory. Initial setup and one-time configuration.
viewWillAppear(_:) Just before the view appears. Refresh information before display.
viewIsAppearing(_:) As the view is appearing, after its traits and geometry are updated. Perform appearance-related configuration that needs current view information.
viewDidAppear(_:) After the view appears. Start animations or visible-screen tasks.
viewWillDisappear(_:) Just before the view disappears. Prepare to leave the screen or stop temporary activity.
viewDidDisappear(_:) After the view disappears. Stop screen-specific work or clean up temporary resources.
viewWillLayoutSubviews() Before the controller lays out its subviews. Respond to layout preparation.
viewDidLayoutSubviews() After the controller lays out its subviews. Perform layout-dependent adjustments.

7.2 Typical View Controller Lifecycle Sequence

loadView()
    |
    v
viewDidLoad()
    |
    v
viewWillAppear(_:)
    |
    v
viewIsAppearing(_:)
    |
    v
viewWillLayoutSubviews()
    |
    v
viewDidLayoutSubviews()
    |
    v
viewDidAppear(_:)
    |
    v
viewWillDisappear(_:)
    |
    v
viewDidDisappear(_:)

Note: Layout callbacks can run multiple times. Appearance and disappearance callbacks can also repeat whenever a controller appears or disappears. The exact sequence depends on presentation, navigation, containment, and layout behavior.

7.3 Difference Between viewDidLoad and viewDidAppear

viewDidLoad() viewDidAppear(_:)
Called after the view hierarchy loads. Called after the view becomes visible.
Used for initial setup. Used for tasks that require the screen to be visible.
Usually called once per loaded view instance. May be called multiple times.
Suitable for configuring controls and bindings. Suitable for starting visible animations or appearance-dependent work.

7.4 Practical Lifecycle Logging Example

import UIKit

class ProfileViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        print("1. View Did Load")
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        print("2. View Will Appear")
    }

    override func viewIsAppearing(_ animated: Bool) {
        super.viewIsAppearing(animated)
        print("3. View Is Appearing")
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print("4. View Did Appear")
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        print("5. View Will Disappear")
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        print("6. View Did Disappear")
    }
}

Run the application, open the profile screen, navigate to another screen, and return. Observe the console output to understand when the lifecycle methods are called.

8. Understanding SwiftUI

SwiftUI is Apple's declarative user interface framework. Developers describe what the interface should display for a given state, and SwiftUI updates the interface when relevant state changes.

8.1 Key Features of SwiftUI

  • Declarative syntax: Describe the desired interface instead of manually updating every visual component.
  • State management: Update the interface when application data changes.
  • Reusable views: Build smaller views and combine them into larger interfaces.
  • Live previews: Preview supported interface changes during development.
  • Cross-platform support: Build interfaces for Apple platforms using a shared framework.
  • Swift integration: Use Swift language features directly in interface code.

8.2 Creating a Basic SwiftUI View

import SwiftUI

struct ContentView: View {

    var body: some View {
        VStack(spacing: 16) {
            Text("Welcome to iOS Development")
                .font(.title)
                .fontWeight(.bold)

            Text("Learning SwiftUI")
                .foregroundStyle(.secondary)

            Button("Get Started") {
                print("Button tapped")
            }
        }
        .padding()
    }
}

Explanation: ContentView conforms to the View protocol. Its body property describes the interface using a vertical stack, text views, and a button.

9. SwiftUI Application Lifecycle

SwiftUI applications commonly use the App protocol as their application entry point. The @main attribute identifies the application structure that starts the app. The Scene declaration describes the interface or window content presented by the application.

9.1 Creating a SwiftUI App

import SwiftUI

@main
struct LearningApp: App {

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

Explanation:

  • @main identifies the application's entry point.
  • App defines the main application structure.
  • body declares the application's scenes.
  • WindowGroup creates a group of windows or scenes containing the main interface.
  • ContentView() is the initial interface displayed inside the window group.

9.2 Monitoring ScenePhase

SwiftUI provides the ScenePhase environment value to observe whether a scene is active, inactive, or in the background.

import SwiftUI

struct ContentView: View {

    @Environment(\.scenePhase) private var scenePhase

    var body: some View {
        Text("Application Lifecycle Example")
            .padding()
            .onChange(of: scenePhase) { oldPhase, newPhase in
                switch newPhase {
                case .active:
                    print("Scene is active")

                case .inactive:
                    print("Scene is inactive")

                case .background:
                    print("Scene entered background")

                @unknown default:
                    print("Unknown scene phase")
                }
            }
    }
}

Explanation: The environment property reads the current scene phase. The onChange modifier responds when the phase changes. This is useful for pausing temporary activities, saving state, and refreshing information when appropriate.

9.3 SwiftUI View Lifecycle Modifiers

Modifier Purpose
onAppear Runs an action when a view appears.
onDisappear Runs an action when a view disappears.
task Starts an asynchronous task associated with a view's lifetime.
onChange Responds when an observed value changes.
refreshable Provides a pull-to-refresh action for supported views.

9.4 onAppear and onDisappear Example

import SwiftUI

struct DashboardView: View {

    var body: some View {
        VStack {
            Text("Dashboard")
                .font(.largeTitle)
        }
        .onAppear {
            print("Dashboard appeared")
            loadDashboardData()
        }
        .onDisappear {
            print("Dashboard disappeared")
        }
    }

    private func loadDashboardData() {
        print("Loading dashboard information")
    }
}

Important: onAppear is not guaranteed to run only once. A view may appear again due to navigation, conditional rendering, or other interface changes. Avoid treating it as a one-time application initialization method.

9.5 Using task for Asynchronous Work

import SwiftUI

struct UserListView: View {

    @State private var users: [String] = []

    var body: some View {
        List(users, id: \.self) { user in
            Text(user)
        }
        .task {
            await loadUsers()
        }
    }

    private func loadUsers() async {
        try? await Task.sleep(for: .seconds(1))
        users = ["Aarav", "Priya", "Rahul"]
    }
}

The task modifier is useful for asynchronous operations such as loading data. SwiftUI manages the task in relation to the view's lifecycle and can cancel it when the view disappears. Developers should still design asynchronous operations to handle cancellation correctly.

10. SwiftUI State Management Concepts

SwiftUI uses property wrappers and observable data models to manage information that affects the interface. When relevant state changes, SwiftUI recalculates the affected view body and updates the displayed interface.

Property Wrapper Purpose Typical Usage
@State Stores local view-owned state. Form input, selected tab, counter.
@Binding Provides read-write access to state owned elsewhere. Child view editing parent state.
@StateObject Creates and owns an ObservableObject reference in a view. Legacy ObservableObject-based view models.
@ObservedObject Observes an externally owned ObservableObject. Receiving an existing view model.
@EnvironmentObject Reads an ObservableObject supplied through the environment. Shared application data.
@Environment Reads values supplied through the environment. Scene phase, color scheme, dismiss action.
@Observable Enables observation for a model using the Observation framework. Modern observable data models.

10.1 @State Example

import SwiftUI

struct CounterView: View {

    @State private var count = 0

    var body: some View {
        VStack(spacing: 15) {
            Text("Count: \(count)")
                .font(.title)

            Button("Increase") {
                count += 1
            }
        }
        .padding()
    }
}

When the button is tapped, the count value changes. SwiftUI detects the state update and refreshes the displayed text.

10.2 @Binding Example

import SwiftUI

struct ParentView: View {

    @State private var username = ""

    var body: some View {
        VStack {
            Text("Username: \(username)")
            UsernameEditor(username: $username)
        }
        .padding()
    }
}

struct UsernameEditor: View {

    @Binding var username: String

    var body: some View {
        TextField("Enter username", text: $username)
            .textFieldStyle(.roundedBorder)
    }
}

The parent owns the username state, while the child receives a binding that allows it to read and update the same value.

11. Understanding UIKit

UIKit is Apple's framework for developing application interfaces on iOS and related platforms. It provides components for views, view controllers, navigation, gestures, animations, tables, collections, and user interaction.

11.1 Important UIKit Components

Component Purpose
UIView Represents a rectangular area used to display content and handle interactions.
UIViewController Manages a screen or portion of an interface.
UILabel Displays text.
UIButton Provides a tappable button.
UITextField Accepts single-line text input.
UITextView Displays or accepts multi-line text.
UITableView Displays information in a vertically arranged list.
UICollectionView Displays flexible collections of items.
UINavigationController Manages a stack-based navigation flow.
UITabBarController Manages multiple sections accessible through a tab bar.
UIScrollView Supports scrolling content.

11.2 Creating a Button in UIKit

import UIKit

class HomeViewController: UIViewController {

    private let actionButton = UIButton(type: .system)

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .systemBackground

        actionButton.setTitle("Continue", for: .normal)
        actionButton.addTarget(
            self,
            action: #selector(buttonTapped),
            for: .touchUpInside
        )

        actionButton.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(actionButton)

        NSLayoutConstraint.activate([
            actionButton.centerXAnchor.constraint(
                equalTo: view.centerXAnchor
            ),
            actionButton.centerYAnchor.constraint(
                equalTo: view.centerYAnchor
            )
        ])
    }

    @objc private func buttonTapped() {
        print("Continue button tapped")
    }
}

This example creates a button programmatically, adds it to the view hierarchy, positions it using Auto Layout, and connects a target-action method to its tap event.

12. SwiftUI vs UIKit

Both SwiftUI and UIKit are used to develop iOS interfaces, but they follow different programming approaches.

Feature SwiftUI UIKit
Programming style Declarative Primarily imperative
Interface definition Swift code describing the desired interface Views configured through code, storyboards, or other interface tools
Lifecycle App, Scene, and View lifecycle APIs App/Scene delegates and UIViewController lifecycle
State updates State-driven interface updates Developers commonly update views explicitly
Navigation NavigationStack and related APIs UINavigationController and presentation APIs
Layout Stacks, grids, modifiers, and layout protocols Auto Layout, constraints, frames, and view layout APIs
Reuse Custom reusable View structures Reusable UIView and UIViewController subclasses
Integration Can host UIKit components Can host SwiftUI views

12.1 When Should You Use SwiftUI?

  • When building a new application with a state-driven interface.
  • When creating reusable interface components.
  • When working with declarative layouts and previews.
  • When developing applications across multiple Apple platforms.
  • When the required interface and platform APIs are well supported by SwiftUI.

12.2 When Should You Use UIKit?

  • When maintaining an existing UIKit application.
  • When a project depends on UIKit-specific components or APIs.
  • When integrating with established UIKit-based libraries.
  • When detailed control over view controller behavior is required.
  • When building complex interfaces using mature UIKit capabilities.

13. Integrating SwiftUI and UIKit

SwiftUI and UIKit can work together in a single application. This is useful when gradually modernizing an existing application or when a project requires a component that is easier to implement using the other framework.

13.1 Displaying SwiftUI Inside UIKit

UIHostingController allows a SwiftUI view to be presented inside a UIKit application.

import SwiftUI
import UIKit

struct WelcomeView: View {

    var body: some View {
        VStack {
            Text("Welcome")
                .font(.largeTitle)

            Text("This is a SwiftUI screen")
        }
        .padding()
    }
}

class HomeViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let swiftUIView = WelcomeView()
        let hostingController = UIHostingController(
            rootView: swiftUIView
        )

        addChild(hostingController)
        view.addSubview(hostingController.view)

        hostingController.view.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([
            hostingController.view.topAnchor.constraint(
                equalTo: view.topAnchor
            ),
            hostingController.view.bottomAnchor.constraint(
                equalTo: view.bottomAnchor
            ),
            hostingController.view.leadingAnchor.constraint(
                equalTo: view.leadingAnchor
            ),
            hostingController.view.trailingAnchor.constraint(
                equalTo: view.trailingAnchor
            )
        ])

        hostingController.didMove(toParent: self)
    }
}

13.2 Displaying UIKit Inside SwiftUI

UIViewRepresentable allows a UIKit UIView to be used as part of a SwiftUI interface.

import SwiftUI
import UIKit

struct CustomUIKitView: UIViewRepresentable {

    func makeUIView(context: Context) -> UILabel {
        let label = UILabel()
        label.text = "UIKit inside SwiftUI"
        label.textAlignment = .center
        label.font = .systemFont(ofSize: 20)
        return label
    }

    func updateUIView(
        _ uiView: UILabel,
        context: Context
    ) {
        uiView.text = "Updated UIKit Component"
    }
}

struct ContentView: View {

    var body: some View {
        CustomUIKitView()
            .frame(height: 60)
            .padding()
    }
}

Explanation: makeUIView creates the UIKit view, while updateUIView updates it when SwiftUI needs to synchronize its state with the represented view.

14. Navigation in UIKit and SwiftUI

14.1 UIKit Navigation Controller

UINavigationController manages a stack of view controllers. A new screen is pushed onto the stack, and the previous screen can be restored by popping the current controller.

let detailVC = DetailViewController()
navigationController?.pushViewController(
    detailVC,
    animated: true
)

// Return to the previous screen
navigationController?.popViewController(animated: true)

14.2 SwiftUI NavigationStack

import SwiftUI

struct NavigationExample: View {

    var body: some View {
        NavigationStack {
            VStack(spacing: 20) {
                Text("Home Screen")

                NavigationLink(
                    "Open Details",
                    destination: DetailScreen()
                )
            }
            .navigationTitle("Home")
        }
    }
}

struct DetailScreen: View {

    var body: some View {
        Text("Detail Screen")
            .navigationTitle("Details")
    }
}

NavigationStack manages a navigation hierarchy in SwiftUI. NavigationLink provides a declarative way to navigate between views.

15. Memory Management and Lifecycle Best Practices

Lifecycle management is closely connected to memory usage and application performance. Developers should release unnecessary resources and avoid retaining objects longer than required.

15.1 Important Best Practices

  • Keep viewDidLoad focused on initial view configuration.
  • Refresh screen-specific information at appropriate appearance events.
  • Stop timers and observers when they are no longer required.
  • Cancel unnecessary asynchronous tasks.
  • Save important data before entering the background.
  • Use weak references in closures when necessary to prevent retain cycles.
  • Avoid performing expensive operations repeatedly during view updates.
  • Respond appropriately to memory warnings.
  • Do not rely on applicationWillTerminate as the only opportunity to save data.
  • Test lifecycle behavior on real devices as well as simulators.

15.2 Avoiding Retain Cycles

class ProfileViewController: UIViewController {

    var onUpdate: (() -> Void)?

    override func viewDidLoad() {
        super.viewDidLoad()

        onUpdate = { [weak self] in
            guard let self = self else { return }
            self.refreshProfile()
        }
    }

    private func refreshProfile() {
        print("Profile refreshed")
    }
}

Using a weak capture prevents the closure from strongly retaining the view controller. This is useful when a closure is stored by an object that may outlive the controller.

16. Common Lifecycle and Framework Mistakes

Mistake Why It Is a Problem Recommended Solution
Loading data repeatedly in viewDidAppear. The method may run each time the screen appears. Choose the correct lifecycle event and cache data when appropriate.
Saving data only during termination. The application may be terminated without receiving the expected callback. Save important changes during normal operation and background transitions.
Updating UIKit views from a background thread. Can cause inconsistent interface behavior. Perform UI updates on the main thread or MainActor.
Assuming onAppear runs only once. SwiftUI views may appear multiple times. Make appearance actions safe to repeat.
Creating unnecessary state properties. Can make data ownership and updates difficult to understand. Use the appropriate state ownership mechanism.
Ignoring task cancellation. Unnecessary work may continue after a view disappears. Use cancellation-aware asynchronous code.
Confusing AppDelegate with SceneDelegate. Application-wide and scene-specific events have different responsibilities. Separate process-level and scene-level logic.
Forgetting child controller containment. Embedded controllers may not receive correct lifecycle and layout behavior. Use addChild, didMove, and the appropriate removal methods.

17. Practical Project: Lifecycle Demonstration Application

Build a small iOS application that demonstrates application state changes, view controller lifecycle methods, and SwiftUI appearance events.

17.1 Project Requirements

  • Create a home screen with a welcome message.
  • Display a button that navigates to a profile screen.
  • Print UIViewController lifecycle events in the Xcode console.
  • Display the current scene phase in a SwiftUI screen.
  • Use onAppear and onDisappear to observe view visibility.
  • Save a small piece of user data before the application enters the background.
  • Test returning to the application after switching to another app.

17.2 Example SwiftUI Lifecycle Screen

import SwiftUI

struct LifecycleDemoView: View {

    @Environment(\.scenePhase) private var scenePhase
    @State private var message = "Application is ready"

    var body: some View {
        VStack(spacing: 20) {

            Text("iOS Lifecycle Demo")
                .font(.title)

            Text(message)
                .multilineTextAlignment(.center)

            Button("Update Status") {
                message = "User interacted with the app"
            }
        }
        .padding()
        .onAppear {
            print("View appeared")
        }
        .onDisappear {
            print("View disappeared")
        }
        .onChange(of: scenePhase) { oldPhase, newPhase in
            switch newPhase {
            case .active:
                message = "Application is active"

            case .inactive:
                message = "Application is inactive"

            case .background:
                message = "Application is in background"

            @unknown default:
                message = "Unknown state"
            }
        }
    }
}

17.3 Expected Learning Outcome

After completing this project, learners should be able to identify lifecycle callbacks, understand how views appear and disappear, observe scene transitions, and explain the differences between UIKit and SwiftUI approaches.

18. iOS Lifecycle Interview Questions and Answers

Q1. What is the iOS application lifecycle?

Answer: The iOS application lifecycle describes the different execution states an application passes through, including not running, inactive, active, background, and suspended. Developers use lifecycle events to manage resources, save information, and prepare the interface for user interaction.

Q2. What is AppDelegate?

Answer: AppDelegate is an object that conforms to UIApplicationDelegate and handles application-level events such as launch configuration and shared application behavior.

Q3. What is SceneDelegate?

Answer: SceneDelegate manages the lifecycle of an individual user-interface scene. It handles scene connection, activation, background transitions, and scene-specific window configuration.

Q4. What is the difference between AppDelegate and SceneDelegate?

Answer: AppDelegate manages application-process-level behavior, while SceneDelegate manages the lifecycle and interface configuration of an individual scene.

Q5. What is UIViewController?

Answer: UIViewController is a UIKit class responsible for managing a screen or a portion of an interface, including its view hierarchy, user interactions, navigation, and lifecycle events.

Q6. What is viewDidLoad?

Answer: viewDidLoad is called after the view controller's view hierarchy has loaded into memory. It is commonly used for initial configuration, setting up controls, and registering required resources.

Q7. What is the difference between viewWillAppear and viewDidAppear?

Answer: viewWillAppear is called just before the view appears, whereas viewDidAppear is called after the view has appeared. The first is useful for preparing the interface, while the second is useful for tasks that require the view to be visible.

Q8. What is SwiftUI?

Answer: SwiftUI is Apple's declarative user interface framework. Developers describe the interface using Swift views, and the framework updates the interface when relevant state changes.

Q9. What is the App protocol in SwiftUI?

Answer: The App protocol defines the structure and entry point of a SwiftUI application. A type conforming to App provides a body property that declares the application's scenes.

Q10. What is ScenePhase?

Answer: ScenePhase is an environment value that represents the current state of a SwiftUI scene. Its common values are active, inactive, and background.

Q11. What is the difference between onAppear and viewDidLoad?

Answer: onAppear is a SwiftUI view lifecycle modifier that runs when a view appears. viewDidLoad is a UIKit view controller callback that runs after the controller's view hierarchy loads. They serve different lifecycle models and are not exact equivalents.

Q12. What is @State in SwiftUI?

Answer: @State stores local, view-owned mutable state. When the value changes, SwiftUI updates the parts of the interface that depend on it.

Q13. What is @Binding?

Answer: @Binding provides read-write access to a value owned by another view or state holder. It allows child views to modify data without owning that data.

Q14. What is the difference between SwiftUI and UIKit?

Answer: SwiftUI uses a declarative, state-driven approach, while UIKit primarily uses an imperative approach with views and view controllers. Both frameworks can be combined in the same application.

Q15. What is UIHostingController?

Answer: UIHostingController is a UIKit view controller that hosts a SwiftUI view. It allows developers to integrate SwiftUI interfaces into UIKit applications.

Q16. What is UIViewRepresentable?

Answer: UIViewRepresentable is a SwiftUI protocol that allows developers to create and manage UIKit UIView components inside SwiftUI interfaces.

Q17. What happens when an iOS application enters the background?

Answer: The application or scene becomes non-visible and may receive limited time to complete important tasks. Developers should save important state, stop unnecessary work, and release resources where possible.

Q18. Is applicationWillTerminate always called?

Answer: No. iOS may suspend and terminate an application without calling applicationWillTerminate. Important information should be saved before termination becomes necessary.

Q19. What is NavigationStack?

Answer: NavigationStack is a SwiftUI container that manages a navigation hierarchy and supports navigation between views.

Q20. What is UINavigationController?

Answer: UINavigationController is a UIKit container view controller that manages a stack of view controllers and supports push and pop navigation.

Q21. Why should UI updates happen on the main thread?

Answer: UIKit interface operations are expected to occur on the main thread. Performing UI updates from background threads can cause inconsistent behavior and runtime problems. MainActor can be used to isolate UI-related work.

Q22. What is the purpose of viewWillDisappear?

Answer: viewWillDisappear is called before a view controller's view disappears. It can be used to prepare for navigation, stop temporary activities, or update screen-related state.

Q23. Can UIKit and SwiftUI be used together?

Answer: Yes. UIHostingController embeds SwiftUI views inside UIKit, while UIViewRepresentable and UIViewControllerRepresentable allow UIKit components to be used inside SwiftUI.

Q24. What is a retain cycle?

Answer: A retain cycle occurs when objects hold strong references to each other, preventing them from being deallocated. Weak or unowned references can help prevent retain cycles when used appropriately.

Q25. What is the purpose of viewDidLayoutSubviews?

Answer: viewDidLayoutSubviews is called after the controller's view lays out its subviews. It is useful when code needs the updated layout geometry, but it should not be used for expensive repeated work.

19. Practical Interview Preparation Checklist

  • Explain all major iOS application states.
  • Describe the responsibilities of AppDelegate and SceneDelegate.
  • Write a basic AppDelegate and SceneDelegate implementation.
  • Explain the UIViewController lifecycle sequence.
  • Differentiate viewDidLoad, viewWillAppear, and viewDidAppear.
  • Explain the SwiftUI App protocol and WindowGroup.
  • Demonstrate ScenePhase with a SwiftUI example.
  • Explain onAppear, onDisappear, and task.
  • Understand @State, @Binding, and observable data models.
  • Compare SwiftUI and UIKit with practical examples.
  • Explain UIHostingController and UIViewRepresentable.
  • Demonstrate navigation using NavigationStack and UINavigationController.
  • Explain background handling, data persistence, and memory management.
  • Practice explaining code examples without relying only on memorized definitions.

20. Practice Exercises

  1. Create a UIKit application that prints all major UIViewController lifecycle callbacks.
  2. Build a SwiftUI screen that displays the current ScenePhase.
  3. Create a counter using @State and explain how the interface updates.
  4. Build a parent-child interface using @Binding.
  5. Implement a navigation flow using UINavigationController.
  6. Implement the same navigation flow using NavigationStack.
  7. Embed a SwiftUI view inside a UIKit application using UIHostingController.
  8. Display a UIKit label inside SwiftUI using UIViewRepresentable.
  9. Test how your application behaves when it enters the background and returns to the foreground.
  10. Explain the difference between application lifecycle events and view controller lifecycle events.

21. Quick Revision Notes

Concept Remember
App lifecycle Describes application execution states.
AppDelegate Manages application-level events.
SceneDelegate Manages individual UI scene events.
UIViewController Manages a UIKit screen or interface section.
viewDidLoad Initial view hierarchy setup.
viewWillAppear Called before the view appears.
viewDidAppear Called after the view appears.
SwiftUI Declarative user interface framework.
App protocol Defines the SwiftUI application structure.
ScenePhase Represents the current scene state.
@State Stores local view-owned state.
@Binding Shares read-write access to state.
UIKit Framework for building iOS interfaces.
UIHostingController Hosts SwiftUI content in UIKit.
UIViewRepresentable Wraps a UIKit view for SwiftUI.
NavigationStack Manages SwiftUI navigation.
UINavigationController Manages UIKit navigation stacks.

22. Important Documentation and Learning Resources

23. Conclusion

Understanding the iOS application lifecycle, view controller lifecycle, SwiftUI, and UIKit is essential for becoming a capable iOS developer. Application lifecycle concepts explain how an app responds to system events, while view controller lifecycle methods explain how individual UIKit screens are loaded, displayed, and removed.

SwiftUI provides a declarative and state-driven approach to interface development, whereas UIKit offers a mature framework with detailed control over views and view controllers. Knowing how to use both frameworks and integrate them when required is valuable for building modern iOS applications and answering technical interview questions confidently.

To explore structured iOS App Development training, visit JustAcademy iOS App Development Training, register for a course demo, or explore the JustAcademy website.

Previous Next
whatsapp